/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package rlpw.util;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.jar.*;

/**
 *
 * @author Ronny
 */
public class ClassUtils {
    @SuppressWarnings("rawtypes")
	public static boolean isChildOf(Class c1, Class c2) {
        if (c1.getName().equals(c2.getName())) {
            return true;
        }
        if (c1.getName().equals(Object.class.getName())) {
            return false;
        }
        return isChildOf(c1.getSuperclass(), c2);
    }

    @SuppressWarnings("rawtypes")
	static public List<Class> getClasses(String packageName) throws Exception {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        return getClasses(loader, packageName);
    }

    @SuppressWarnings("rawtypes")
	static public List<Class> getClasses(Package pack) throws Exception {
        return getClasses(pack.getName());
    }

    @SuppressWarnings("rawtypes")
	static public List<Class> getClasses(Class clazz) throws Exception {
        return getClasses(clazz.getPackage());
    }

    @SuppressWarnings("rawtypes")
	static private List<Class> getClasses(ClassLoader loader, String packageName) throws Exception {
        List<Class> classes = new ArrayList<Class>();
        String path = packageName.replace('.', '/');
        Enumeration<URL> resources = loader.getResources(path);
        if (resources != null) {
            while (resources.hasMoreElements()) {
                String filePath = resources.nextElement().getFile();
                // WINDOWS HACK
                if (filePath.indexOf("%20") > 0) {
                    filePath = filePath.replaceAll("%20", " ");
                }
                if (filePath != null) {
                    if ((filePath.indexOf("!") > 0) & (filePath.indexOf(".jar") > 0)) {
                        String jarPath = filePath.substring(0, filePath.indexOf("!")).substring(filePath.indexOf(":") + 1);
                        // WINDOWS HACK
                        if (jarPath.indexOf(":") >= 0) {
                            jarPath = jarPath.substring(1);
                        }
                        classes.addAll(getFromJARFile(jarPath, path));
                    } else {
                        classes.addAll(getFromDirectory(new File(filePath), packageName));
                    }
                }
            }
        }
        return classes;
    }

    @SuppressWarnings("rawtypes")
	static private List<Class> getFromDirectory(File directory, String packageName) throws Exception {
        List<Class> classes = new ArrayList<Class>();
        if (directory.exists()) {
            for (File file : directory.listFiles()) {
                if (file.isFile() && file.getName().endsWith(".class")) {
                    String name = packageName + '.' + stripFilenameExtension(file.getName());
                    Class<?> clazz = Class.forName(name);
                    classes.add(clazz);
                } else if(file.isDirectory()) {
                    classes.addAll(getFromDirectory(file, packageName+"."+file.getName()));
                }
            }
        }
        return classes;
    }

    @SuppressWarnings("rawtypes")
	static private List<Class> getFromJARFile(String jar, String packageName) throws FileNotFoundException, IOException, ClassNotFoundException {
        List<Class> classes = new ArrayList<Class>();
        JarInputStream jarFile = new JarInputStream(new FileInputStream(jar));
        JarEntry jarEntry;
        do {
            jarEntry = jarFile.getNextJarEntry();
            if (jarEntry != null) {
                String className = jarEntry.getName();
                if (className.endsWith(".class")) {
                    className = stripFilenameExtension(className);
                    if (className.startsWith(packageName)) {
                        classes.add(Class.forName(className.replace('/', '.')));
                    }
                }
            }
        } while (jarEntry != null);
        return classes;
    }

    private static String stripFilenameExtension(String className) {
        return className.substring(0, className.lastIndexOf("."));
    }


}
